<!DOCTYPE html> 
<html>
<head>
<title>Skyline75489</title>
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<link rel="stylesheet" href="../static/styles/github.css">
<link rel="stylesheet" href="../static/post.css">
</head>
<body>

<div class="wrapper">
<div class="header">
	<span class="blog-name">Skyline75489</span>

<a class="nav" href="../index.html">Home</a>
<a class="nav" href="about.html">About</a>
</div>
<div class="content">

<h1>Swift学习笔记(四)——类与对象</h1>
<p>Swift对面向对象提供了良好的支持，下面介绍几个其独有的特性。</p>
<h3>懒加载属性</h3>
<p>Swift在语言层面上提供了类中懒加载属性的支持，使用<code>lazy</code>作为关键字：</p>
<pre><code class="lang-swift">class Renderer {
    lazy var loader = Loader()
    var data = [String]()
    var render() {
        // Do something...
    }
}

let renderer = Renderer()
renderer.data.append(&quot;## Hello&quot;)
renderer.data.append(&quot;## Hello Again&quot;)
// loader不会被创建
renderer.loader.loadData()
// loader现在才会被创建
</code></pre>
<h3>属性计算与属性观察器</h3>
<p>类似于C#和Python中的<code>@property</code>，Swift也支持给属性赋值或者取出值时进行计算：</p>
<pre><code class="lang-swift">class Square {
    var length = 0.0
    var size: Double { // 必须显式声明类型
        get {
            return length * length
        }
        set (newSize) {
            length = sqrt(newSize)
        }
    }
}
</code></pre>
<p>也可以用下面的方法将属性设置成只读的：</p>
<pre><code class="lang-swift">class Square {
    var length = 0.0
    var size: Double {
            return length * length
        }
    }
}
</code></pre>
<p>除了 set 和 get ，Swift还提供了更细粒度的针对属性值变化的观察方法——属性观察器 willSet 和 didSet ：</p>
<pre><code class="lang-swift">class Person {
    var age: Int = 0 {
        willSet(newAge) {
            println(&quot;About to set new age&quot;)
        }
        didSet {
            println(&quot;Did set new age&quot;)
        }
    }
}
</code></pre>
<p>willSet 和 didSet在每次属性赋值时都会被调用，不管新值是否与旧值相同，但是在init函数中给属性赋值时则不会被调用。</p>
<h3>使用下标访问属性</h3>
<p>Swift提供了subscript语法，可以使用下标来访问类的属性，类似于Python中的<code>__getitem__</code></p>
<pre><code class="lang-swift">class Dict {
    subscript(key: String) -&gt; String {
        get {
        // 取值
        }

        set(newValue) {
        // 赋值
        }
}
</code></pre>
<h3>Convenience初始化器</h3>
<p>Swift支持两个层次的初始化，一种叫做Designated，另一张叫做Convenience，顾名思义，是一种用于方便初始化过程的初始化器。</p>
<pre><code class="lang-swift">class Person {
    var name: String
    init(name: String) {
        self.name = name
    }
    convenience init() {
        self.init(name: &quot;Unknown&quot;)
    }
}
</code></pre>
<p>例如上面的代码，我们便可以使用无参数的init来快速初始化一个Person实例。</p>
<p>你可能要问，为什么不在原来的init里使用默认参数，而是单独再加一个初始化函数呢？我个人的理解是，当初始化参数比较多，而且类型不同时，使用默认参数会使得初始化函数变得过于复杂，而且可读性差。使用Convenicence可以把这些参数全部解耦到不同的函数里，使得代码更加漂亮。例如SwiftJSON里就大量地使用了这一特性:</p>
<pre><code class="lang-swift">public convenience init(url:String) {//...}
public convenience init(nsurl:NSURL) {//...}
public convenience init(data:NSData) {//...}
</code></pre>
<p>有了这些初始化函数，我们就可以很方便地使用String,URL,NSData等来构造JSON对象。</p>
<h3>与Struct的区别</h3>
<p>和C#之类的现代高级语言一样，Swift的结构体类型也是可以在其中定义属性和方法的，用法与类相似：</p>
<pre><code class="lang-swift">struct A{
     var a = 10;
     func sayHello() {
         println(&quot;hello&quot;)
     }
}
</code></pre>
<p>类和结构体的主要区别有以下几点：</p>
<ul>
<li>结构体是值类型，类是引用类型，这是最大也是最重要的区别了</li>
<li>结构体有自动生成的成员初始化函数(Memberwise Initializer)，类没有</li>
<li>类可以使用deinit函数做反初始化，结构体不可以</li>
<li>类支持方法继承和重载，结构体不支持</li>
</ul>
<p>简单说来，结构体更适合用来封装若干简单的数据，例如CGRect之类。如果需要太多的逻辑和操作，还是用类更合适。</p>


</div>
</div>
<script src="../static/highlight.pack.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
</body>

</html>
